<?php

namespace App\Console\Commands\Mybank;

use App\Exceptions\BaseException;
use App\Kuafu\Mqtt\Model\Log;
use App\Kuafu\Mybank\Enum\MybankAccountEnum;
use App\Kuafu\Mybank\Model\MybankBillRecordModel;
use App\Kuafu\Mybank\Model\MybankEntryModel;
use App\Kuafu\Mybank\Model\MybankFuyouBillRecordModel;
use App\Kuafu\Pay\Model\PayStreamMappingModel;
use App\Kuafu\Pay\Model\PayStreamModel;
use App\Kuafu\Pay\Model\RefundStreamModel;
use App\Kuafu\Pay\Model\ShopPaymentModel;
use App\Kuafu\Shop\Model\ShopPaymentsModel;
use App\Library\FeiShu\SendFs;
use App\Remote\FuYou\FuYouFundsTransferRemote;
use Carbon\Carbon;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Console\Command;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

class SyncFuyouBillCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'mybank:syncFuyouBillCommand {whichDay?}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '网商：富有账单拉取';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * @return int
     * @throws ContainerExceptionInterface
     * @throws GuzzleException
     * @throws NotFoundExceptionInterface
     */
    public function handle(): int
    {
        if (isTest()) {
            return 0;
        }
        $path                   = $this->input->getArgument("whichDay") ?? Carbon::yesterday()->format("Ymd");
        $shopPaymentsCollection = ShopPaymentModel::query()
                                                  ->where('payChannel', PayStreamModel::PAY_CHANNEL_FY)
                                                  ->whereRaw("payConfig -> '$.reserved_fy_term_id' != ''")
                                                  ->get()
                                                  ->map(function (ShopPaymentModel $v) {
                                                      return $v->toArray() + jsonToArr($v->payConfig);
                                                  })
                                                  ->values();

        $storage = Storage::disk("fuyouBill-ftp");

        if ($storage->exists($path)) {
            try {
                // 同步富友账单数据
                logMsg("【 网商 】【 富友 】 【 同步富友账单数据 】 【 {$path} 】", ["executeTime" => $path], true, true,
                    SendFs::ROBOT_BATCH_BILL_MATCH);
                $this->syncFyBillRecord($storage, $path, $shopPaymentsCollection);

                // 同步夸父账单数据
                logMsg("【 网商 】【 富友 】 【 同步夸父账单数据 】 【 {$path} 】", ["executeTime" => $path], true, true,
                    SendFs::ROBOT_BATCH_BILL_MATCH);
                $this->syncKfBillRecord($path);
            } catch (\Exception $exception) {
                logException(
                    "【 网商 】【 富友 】 【 对账生成失败 】 【 {$path} 】",
                    $exception,
                    ["day" => $path],
                    true,
                    true
                );
            }
        } else {
            logMsg("【 网商 】【 富友 】 【 当前日期对账文件尚未生成 】 【 {$path} 】", ["date" => $path], true, true,
                SendFs::ROBOT_BATCH_BILL_MATCH);
            $this->getOutput()->error("【 {$path} 】 当前日期对账文件尚未生成");
        }

        return 0;
    }

    /**
     * @param FilesystemAdapter $storage
     * @param string $path
     * @param Collection $shopPaymentsCollection
     * @throws ContainerExceptionInterface
     * @throws FileNotFoundException
     * @throws NotFoundExceptionInterface
     */
    public function syncFyBillRecord(FilesystemAdapter $storage, string $path, Collection $shopPaymentsCollection)
    {
        $prefix              = "fuyouBill";
        $fyWhiteMerchantList = [
            '0001000F5937721'
        ];

        MybankFuyouBillRecordModel::query()->where("transactionDate", $path)->delete();
        collect($storage->allFiles($path))->each(function (string $filePath) use (
            $prefix,
            $path,
            $storage,
            $shopPaymentsCollection,
            $fyWhiteMerchantList
        ) {
            $fileSystem   = getFileSystem();
            $realFilePath = getTmpDir($prefix . "/" . $filePath);
            $pathInfo     = pathinfo($realFilePath);
            if (!$fileSystem->isDirectory($pathInfo["dirname"])) {
                $fileSystem->makeDirectory($pathInfo["dirname"], 0777, true);
            }
            $fileSystem->put($realFilePath, $storage->get($filePath));

            File::lines($realFilePath)->each(function ($line) use ($shopPaymentsCollection, $fyWhiteMerchantList) {
                if (!empty($line)) {
                    list(
                        $fyMerchantId,//商户号
                        $cardNum,//卡号
                        $cardAttr,//卡属性
                        $referenceNum,//参考号
                        $transactionType,//交易类型
                        $terminalNum,//终端号
                        $merchantOrderNo,//商户订单号
                        $channelOrderNo,//渠道订单号
                        $transactionAmount,//交易金额
                        $transactionStatus,//交易状态
                        $transactionStatusDesc,//交易状态说明
                        $transactionCompletionTime,//交易完成时间
                        $transactionDate,//交易日期
                        $originalTransactionOrderNo,//原交易订单号
                        $transactionFee,//交易手续费
                        $externalOrderNo,//外部订单号
                        $transactionCode,//交易代码
                        $isPreferentialRate,//是否优惠费率
                        $merchantDiscountRate,//商户扣率
                        $errorTransactionSign,//差错交易标识
                        $remark//备注
                        ) = explode("|", $line);


                    $transactionFee            = $transactionFee * 100;
                    $transactionAmount         = ($originalTransactionOrderNo ? "-" . $transactionAmount : $transactionAmount) * 100;
                    $transactionCompletionTime = strtotime($transactionCompletionTime);
                    $merchantDiscountRate      = convertEncoding($merchantDiscountRate);


                    // 判断终端号是否存在
                    if (!$terminalNum) {
                        return true;
                    }

                    if ($terminalNum == 1) {
                        return true;
                    }


                    // 校验商户号是否在白名单里
                    if (!in_array($fyMerchantId, $fyWhiteMerchantList)) {
                        return true;
                    }

                    // 结算商户号
                    $settleShopId = $shopPaymentsCollection->where('reserved_fy_term_id', $terminalNum)
                                                           ->first()['shopId'] ?? 0;

                    if ($settleShopId) {


                        if (empty($originalTransactionOrderNo)) {
                            // shopId 根据订单支付流水表重新去查
                            $payInfo = PayStreamMappingModel::where('payNo', $merchantOrderNo)
                                                            ->select(['shopId', 'payNo', 'bizId'])
                                                            ->first();
                        } else {
                            $payInfo = RefundStreamModel::query()->where('refundNo', $merchantOrderNo)
                                                        ->select(['shopId', 'refundNo as payNo', 'orderId as bizId'])
                                                        ->first();
                        }

                        $shopId    = $payInfo->shopId;
                        $kfOrderNo = $payInfo->bizId;

                        $mybankEntryModel = MybankEntryModel::query()
                                                            ->whereHas("shopBindRel",
                                                                function ($query) use ($shopId) {
                                                                    $query->where("shopId", $shopId);
                                                                })->first();

                        $mybankMerchantId = attributeGet($mybankEntryModel, "merchantId", "");

                        $createdAt = $updatedAt = time();

                        $insertData = compact(
                            "fyMerchantId",//商户号
                            "cardNum",//卡号
                            "cardAttr",//卡属性
                            "referenceNum",//参考号
                            "transactionType",//交易类型
                            "terminalNum",//终端号
                            "merchantOrderNo",//商户订单号
                            "channelOrderNo",//渠道订单号
                            "transactionAmount",//交易金额
                            "transactionStatus",//交易状态
                            "transactionStatusDesc",//交易状态说明
                            "transactionCompletionTime",//交易完成时间
                            "transactionDate",//交易日期
                            "originalTransactionOrderNo",//原交易订单号
                            "transactionFee",//交易手续费
                            "externalOrderNo",//外部订单号
                            "transactionCode",//交易代码
                            "isPreferentialRate",//是否优惠费率
                            "merchantDiscountRate",//商户扣率
                            "errorTransactionSign",//差错交易标识
                            "remark",//备注
                            "shopId",
                            "settleShopId",
                            "mybankMerchantId",
                            "kfOrderNo",
                            "createdAt",
                            "updatedAt"
                        );

                        MybankFuyouBillRecordModel::query()->insert($insertData);
                    }
                }
//                }
            });

        });
    }

    /**
     * 同步账单数据
     *
     * @param string $path
     * @throws BaseException
     * @throws GuzzleException
     */
    public function syncKfBillRecord(string $path)
    {
        //富友结算汇总信息写入
        MybankFuyouBillRecordModel::query()->where("transactionDate", $path)->groupBy("shopId")->select([
            DB::raw('sum(transactionFee) as transactionFeeTotal'),
            DB::raw('sum(transactionAmount) as transactionAmountTotal'),
            "fyMerchantId",
            "shopId",
            "transactionDate"
        ])->get()->sortBy("transactionDate")->each(function ($billGroup) use ($path) {
            $this->billRecordInsert(
                $billGroup->shopId,
                $billGroup->transactionDate,
                $billGroup->fyMerchantId . "1" . $billGroup->shopId . $billGroup->transactionDate,
                $billGroup->transactionAmountTotal - $billGroup->transactionFeeTotal,
                MybankBillRecordModel::INCOME_TRANS_TYPE,
                vsprintf(
                    "富友 【%s】结算汇总 【%s】交易汇总 【%s】 手续费 【%s】",
                    [
                        $billGroup["transactionDate"],
                        $billGroup->transactionAmountTotal - $billGroup->transactionFeeTotal,
                        $billGroup->transactionAmountTotal,
                        $billGroup->transactionFeeTotal
                    ]
                )
            );

        });

        $merchantInfo = MybankAccountEnum::getFyAccount();
        //富友清算汇总信息写入
        $nextDay            = Carbon::parse($path)->modify("+1 days")->format("Ymd");
        $fuYouFundsTransfer = FuYouFundsTransferRemote::queryChnlPayAmt(
            $merchantInfo['merchantId'],
            $nextDay,
            $nextDay,
            0,
            100
        );

        if (!empty($fuYouFundsTransfer['mchntList']) && $fuYouFundsTransfer['count'] > 0) {
            // 获取 未结算的所有账单
            $lastedRecord = MybankBillRecordModel::query()
                                                 ->where("transType", MybankBillRecordModel::WITHDRAW_TRANS_TYPE)
                                                 ->where("source", MybankBillRecordModel::SOURCE_CANTEEN)
                                                 ->where('flagMark', 1)
                                                 ->orderByDesc('id')
                                                 ->first();

            $recordList = MybankBillRecordModel::query()
                                               ->where("transType", MybankBillRecordModel::INCOME_TRANS_TYPE)
                                               ->where("source", MybankBillRecordModel::SOURCE_CANTEEN)
                                               ->where('id', '>', $lastedRecord->id)
                                               ->get();

            $groupList = $recordList->groupBy('shopId')->map(function ($item) {
                return $item->sum('transAmount');
            });

            $fyTransferOrder  = $fuYouFundsTransfer['mchntList']['mchnt'];
            $fyTransferAmount = $fyTransferOrder['pay_amt'];

            if (bccomp($fyTransferAmount, $groupList->sum()) !== 0) {
                // 金额不一致
                \Illuminate\Support\Facades\Log::channel('mybank')->error('富友:堂食余额结算与记录不符',
                    [
                        '富友转账金额' => $fyTransferAmount,
                        '本地记录金额' => $groupList->sum(),
                        'fsNotifyUids' => [
                            '3fgc8798'
                        ],
                    ],
                );
                return;
            }
            $groupList->each(function ($item, $shopId) use ($nextDay, $recordList, $merchantInfo) {
                $remark = '';
                $recordList->where('shopId', $shopId)->each(function ($record) use (&$remark) {
                    $remark .= $record->remark . PHP_EOL;
                });
                $this->billRecordInsert(
                    $shopId,
                    $nextDay,
                    $merchantInfo['merchantId'] . $shopId . "01" . $nextDay,
                    $item,
                    MybankBillRecordModel::WITHDRAW_TRANS_TYPE,
                    $remark
                );
            });
        }
    }

    /**
     * @param int $shopId
     * @param int $day
     * @param string $transId
     * @param int $transAmount
     * @param int $transType
     * @param string $remark
     */
    public function billRecordInsert(
        int $shopId,
        int $day,
        string $transId,
        int $transAmount,
        int $transType,
        string $remark
    ) {
        MybankBillRecordModel::query()
                             ->where("transId", $transId)
                             ->where("source", MybankBillRecordModel::SOURCE_CANTEEN)
                             ->update(["isDeleted" => 1, "updatedAt" => time()]);
        MybankBillRecordModel::query()->insert([
            "shopId"               => $shopId,
            "source"               => MybankBillRecordModel::SOURCE_CANTEEN,
            "transDate"            => strtotime($day),
            "transType"            => $transType,
            "displayTransType"     => MybankBillRecordModel::MAPPING_TRANS_TYPE[$transType],
            "transId"              => $transId,
            "transStatus"          => MybankBillRecordModel::TRANS_STATUS_SUC,
            "transDesc"            => $remark,
            "billDate"             => strtotime($day),
            "transAmount"          => $transAmount,
            "afterRemainingAmount" => 0,
            "remark"               => $remark,
            "createdAt"            => time(),
            "updatedAt"            => time()
        ]);
    }
}
